#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>

#include "../../src/thread.h"

static thread_t tid[100000];

static double fibtab[100000];

int cmpt = 1;

static int FIBO_SIZE;

double getTime(){
  struct timeval tv;
  gettimeofday(&tv,NULL);
  return 1000*tv.tv_sec+tv.tv_usec/1000.0;
}

void* fibo (void * n){
  if(fibtab[*(int*)n]  != -1)
    thread_exit(fibtab + *(int*)n);

  else{
    double *retval1; 
    double *retval2;
    int a = *(int*)n - 1;
    int b = *(int*)n - 2;

    thread_t *t1 = tid + cmpt++;
    thread_t *t2 = tid + cmpt++;

    thread_create(t1, (void *(*)(void *)) fibo, &a); 
    thread_create(t2, (void *(*)(void *))fibo, &b);
    
    thread_join(*(t1), (void**)&retval1);
    thread_join(*(t2), (void**)&retval2);        

    if(b == FIBO_SIZE - 2)
      printf("FIBO[%d] = %g\n",b,fibtab[b]);
    if(a == FIBO_SIZE - 1)
      printf("FIBO[%d] = %g\n",a,fibtab[a]);    
    
    fibtab[*(int*)n] = fibtab[a] + fibtab[b];
    thread_exit(fibtab + *(int*)n);
  }
}

int main(){
  printf("Entrer un entier: \n");
  scanf("%d",&FIBO_SIZE);
  
  printf("\n.......Calcul de FIBO(%d) ..... \n",FIBO_SIZE); 

  /* On initialise le tableau */
  int i;
  fibtab[0] = 0;
  if(FIBO_SIZE > 0)
    fibtab[1] = 1;
  for(i = 2; i <= FIBO_SIZE; i++)
    fibtab[i] = -1;
 
  /* On calcule fibo(n) */
  double * resultat;
  if(FIBO_SIZE > 1){
    printf("FIBO[%d] = %g\n",0,fibtab[0]);
    printf("FIBO[%d] = %g\n",1,fibtab[1]);
    printf("......\n");
  }
  double t1 = getTime();
  thread_create(tid,fibo,(void *)&FIBO_SIZE);
  thread_join(*tid , (void**)&resultat);
  double t2 = getTime();

  /* On affiche le résultat */
  printf(".......Resultat FIBO");
  printf("[%d] = %g\n",FIBO_SIZE,*resultat);
  printf("   [Cout de calcul = %g ms]\n", t2 - t1);
  printf(" [Nombre de threads utilisés : %d]\n",cmpt);
  return EXIT_SUCCESS; 
}
